# -*- coding: utf-8 -*-
import socket
import numpy as np
import struct
import time
import pandas as pd
import matplotlib.pyplot as plt
import math

from keras.utils import plot_model
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM, Dense, Activation
from keras.callbacks import EarlyStopping
from keras.models import load_model
from keras.optimizers import SGD
#from hpelm import ELM
#from hpelm import HPELM
#from hpelm import modules

scaler = MinMaxScaler(feature_range=(0, 1))

recv_count = 0
lstm_model = load_model('yu_model.h5')
dataset = [0, 1, 2]  # save data for training
dataset.clear()
ann_model = 0  #:0 lstm 1:ann 2:elm
bRetrain = 0  #
print("*********1 Load keras begin  **********************")
from keras.models import load_model

print("*********  Load keras success**********************")

print("*********2 Load keras module  **********************")
new_model = load_model('my_model.h5')
print("*********  Load keras success  ********************")

if (0 == ann_model):
    print("Machine Learning Algorithm: LSTM")
else:
    print("Machine Learning Algorithm: None")


def predict(x):
    xx = np.array([x])
    x_test = np.reshape(xx, (1, xx.shape[1], 1))

    y_predict = new_model.predict(x_test)
    res = y_predict.tolist()
    # print(x_test, y_predict)
    return res[0][0]


#print("*********3 Init server begin  **********************")
#sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#IPV4,TCP协议
#sock.bind(('127.0.0.1',50001))#绑定ip和端口，bind接受的是一个元组
#sock.listen(5)#设置监听，其值阻塞队列长度，一共可以有5+1个客户端和服务器连接

print("*********  Init server ok    **********************")





# RNN Model
def RNNModel(x_train, y_train, x_test, y_test):
    global bRetrain
    x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))
    x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1))

    model = Sequential()
    model.add(LSTM(input_shape=(None, 1), units=50, return_sequences=True))
    model.add(LSTM(100, return_sequences=False))
    model.add(Dense(units=1))
    model.add(Activation('linear'))

    model.compile(loss='mse', optimizer='rmsprop')
    early_stop = EarlyStopping(monitor='val_loss', patience=5)
    model.fit(x_train, y_train,
              batch_size=10, # old 100
              epochs=50, # old 30
              # validation_split = 0.2,
              validation_data=(x_test, y_test),
              callbacks=[early_stop])
    model.save('yu_model.h5')
    predict = model.predict(x_test)
    print(predict)
    bRetrain = 1
    return model


# build LSTM model
def build_model():
    model = Sequential()
    model.add(LSTM(input_shape=(None, 1), units=50, return_sequences=True))
    model.add(LSTM(100, return_sequences=False))
    model.add(Dense(units=1))
    model.add(Activation('linear'))

    model.compile(loss='mse', optimizer='rmsprop')
    return model


# train the model
def train_model(x_train, train_y, x_test, test_y):
    x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))
    x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1))
    model = build_model()
    #plot_model(model,to_file='model.png',show_shapes=True)
    try:
        early_stop = EarlyStopping(monitor='val_loss', patience=50)
        model.fit(x_train, train_y, batch_size=10, epochs=100,
                  validation_split=0.2, callbacks=[early_stop])
        model.save('yu_model.h5')
        predict = model.predict(x_test)
        print(model.input.name)
        print(model.output.name)
        predict = np.reshape(predict, (predict.size,))
    except KeyboardInterrupt:
        print(predict)
        print(test_y)
    return model


# gen dataset
def gen_datases(datasets, sequence_length=10, split=0.8):
    datasets = np.array(datasets).astype(float)

    datasets = datasets.reshape(len(datasets),1)
    data = []
    for i in range(len(datasets) - sequence_length ):
        data.append(datasets[i: i + sequence_length + 1])
    reshaped_data = np.array(data).astype('float64')
    # np.random.shuffle(reshaped_data)
    #
    x = reshaped_data[:, :-1]
    y = reshaped_data[:, -1]
    split_boundary = int(reshaped_data.shape[0] * split)
    train_x = x[: split_boundary]
    test_x = x[split_boundary:]
    # train_x = x
    # train_y = y
    # test_x = x
    # test_y = y
    train_y = y[: split_boundary]
    test_y = y[split_boundary:]
    print("!!!!!!!!!!!!!!!!!!!train.shape=====================================") #152 10 1  #152 1
    print(train_x.shape)
    print(train_y.shape)
    print("!!!!!!!!!!!!!!!!!!!test.shape=====================================") #38 10 1   #38 1
    print(test_x.shape)
    print(test_y.shape)
    train_model(train_x, train_y, test_x, test_y)
    return train_x, train_y, test_x, test_y


def trainning(datasets):
    global lstm_model
    global ann_model

    train_x, train_y, test_x, test_y = gen_datases(datasets)  # gen data
    if (0 == ann_model):
        lstm_model = RNNModel(train_x, train_y, test_x, test_y)  # train
    else:
        print("para errer")
    # do nothing
    return lstm_model


def predicting(model, x_predict):
    global bRetrain
    global ann_model
    x_predict = np.array([x_predict])

    # if(bRetrain & ann_model):
    if (bRetrain and (1 == ann_model)):
        x_test = np.reshape(x_predict, (1, x_predict.shape[1]))
    elif (bRetrain and (2 == ann_model)):
        x_test = np.reshape(x_predict, (1, x_predict.shape[1]))
    else:
        x_test = np.reshape(x_predict, (1, x_predict.shape[1], 1))
    print("x_test.shape")
    print(x_test.shape)
    printx_test = np.array(x_test)
    print("printx_test======", printx_test) #(1, 10, 1)
    y_predict = model.predict(x_test)
    print("y_predict.shape")
    print(y_predict.shape)
    printy_predict = np.array(y_predict)
    print("printy_predict======", printy_predict)  #(1, 1)
    res = y_predict.tolist()
    return res[0][0]


def addDataset(msgid, msg):
    global dataset
    global lstm_model
    # print(msgid)
    if (1024 != msgid):
        return
    if (len(dataset)):
        dataset.append(msg[-1])
    else:
        msg = list(msg)
        dataset = msg
    if (len(dataset) >= 200):
        print("training the model ...... wait ........\n")
        lstm_model = trainning(dataset)
        printDataSet=np.array(dataset)
        print("printDataSet======", printDataSet) #200个数
        dataset.clear()


print("*********  \n * \n *\n        server is running now!!!!!!!!!!!!!!!!!!! \n**********************")


onu_req=0
while onu_req<=200:

    recv=[9,7,6,4,6,7,8,3,7,10,5,6,5,4,5,6,6,7,4,3,6,9,5,9,8,6,6,5,4,8,5,11,2,6,3,7,5,9,5,5,9,5,7,3,9,7,6,5,6,4,9,7,3,5,7,5,9,8,3,3,4,5,2,6,5,9,5,5,7,6,4,6,11,4,4,3,1,7,2,10,3,3,9,5,4,8,7,6,4,7,4,8,3,6,7,10,4,8,6,6,4,4,6,5,4,8,8,3,3,2,10,2,4,10,3,5,6,8,6,4,6,6,3,7,5,3,5,5,7,3,3,4,6,4,9,8,3,8,5,6,7,8,8,5,6,4,3,5,8,8,7,10,5,7,4,4,10,8,
9,7,6,4,6,7,8,3,7,10,5,6,5,4,5,6,6,7,4,3,6,9,5,9,8,6,6,5,4,8,5,11,2,6,3,7,5,9,5,5,9,5,7,3,9,7,6,5,6,4,9,7,3,5,7,5,9,8,3,3,4,5,2,6,5,9,5,5,7,6,4,6,11,4,4,3,1,7,2,10,3,3,9,5,4,8,7,6,4,7,4,8,3,6,7,10,4,8,6,6,4,4,6,5,4,8,8,3,3,2,10,2,4,10,3,5,6,8,6,4,6,6,3,7,5,3,5,5,7,3,3,4,6,4,9,8,3,8,5,6,7,8,8,5,6,4,3,5,8,8,7,10,5,7,4,4,10,8]
    #a=[1,2,3]
    #s1=str(a)# 将发送数据转化为String
    msg = recv[onu_req:onu_req+10]
    #print(msg)

    #预测开始 ret为返回值
    addDataset(1024, msg)
    res = predicting(lstm_model, list(msg))
    if (res<=0):
        res = 0
    if (res > 100):
        res = 100
    ret = int(res + 0.5)
    print("predict value = %d \r\n", res, "======onu_req=:", onu_req)

    onu_req += 1






